#include "mwerabase.h"
#include <iostream>

using namespace std;

MweraBase::MweraBase(){
}

Graph* MweraBase::getGraph(){
	return &(this->gr);
}

void MweraBase::checkLinks(){
    vector<Link*> links = this->gr.getLinks(); //Liste des liens
    vector<Link*>::iterator currentL = links.begin(); //Iterateur pour parcourir la liste des liens
    while(currentL != links.end()){
        //Si le lien n'est pas un bort d'obstacle
        if(!this->isInAnObstacle((*currentL))){
            //Si il y a une intersection avec un obstacle
            if(this->intersectAnObstacle((*currentL))){
                //Supprime le lien
                this->gr.removeLink((*currentL));
            }
        }
        currentL++;
    }
}
void MweraBase::createObstacle(vector<Point*> obstacle){
    vector<Point*> oldPoints = this->getPoints(); //Liste des point déjà existant
    vector<Point*>::iterator currentPO; //Iterateur pour les points de l'obstacle
    vector<Point*>::iterator currentP; //Iterateur pour les ancien points
    Point* last = NULL;

    //Creation de l'obstacle
    currentPO = obstacle.begin();
    while(currentPO != obstacle.end()){
        //Creation du point
        this->createPoint((*currentPO),false);
        if(last!=NULL){
            //Creation du bord de l'obstacle
            this->createLink(last,(*currentPO));
        }
        //Creation des liens entre l'ancien points et le points courant de l'obstacle
        currentP = oldPoints.begin();
        while(currentP != oldPoints.end()){
            this->createLink((*currentP),(*currentPO));
            currentP++;
        }
        last = (*currentPO);
        currentPO++;
    }
    //Creation du dernier bord de l'obstacle
    this->createLink(last,(*obstacle.begin()));

    //Ajout de l'obstacle dans la liste des obstalces
    this->obstacles.push_back(obstacle);

    //Demande de verification des liens
    this->checkLinks();
}
Point* MweraBase::createPoint(int x,int y,bool autoLink){
    return this->createPoint(new Point(x,y),autoLink);
}
Point* MweraBase::createPoint(Point* p,bool autoLink){
    Point* pt  = this->gr.createPoint(p);
    if(autoLink){
        vector<Point*> points = this->getPoints();
        vector<Point*>::iterator current = points.begin();
        while(current != points.end()){
            this->createLink(p,(*current));
            current++;
        }
    }
    return pt;
}
vector<Point*> MweraBase::getPoints(){
    return this->gr.getPoints();
}
vector<Link*> MweraBase::getLinks(){
    return this->gr.getLinks();
}
vector< vector<Point*> > MweraBase::getObstacles(){
    return this->obstacles;
}
void MweraBase::createLink(Point* p1,Point* p2){
    this->gr.createLink(p1,p2);
}
bool MweraBase::isInAnObstacle(Link* link){
    vector<vector<Point*> >::iterator currentO = this->obstacles.begin(); //Iterateur pour parcourir les obstacle
    bool ret = false; //Valeur de retour
    //Pour tous les obstacles
    while(!ret && currentO != this->obstacles.end()){
        vector<Point*>::iterator currentP = currentO->begin();
        Point* last = NULL;
        //Pour tous les points de l'obstacle
        while(!ret && currentP != currentO->end()){
            if(last != NULL){
                //On regarde si le liens est égale a un bort de l'obstacle
                if( ((*link->getP1()) == (*last) && (*link->getP2()) == (**currentP)) || ((*link->getP1()) == (**currentP) && (*link->getP2()) == (*last)) ){
                    ret = true;
                }
            }
            last = (*currentP);
            currentP++;
        }
        //On regarde si le liens est égale au dernier bort de l'obstacle
        if( ((*link->getP1()) == (*last) && (*link->getP2()) == (**(currentO->begin()))) || ((*link->getP1()) == (**(currentO->begin())) && (*link->getP2()) == (*last)) ){
            ret = true;
        }
        currentO++;
    }
    return ret;
}
bool MweraBase::intersectAnObstacle(Link* link){
    bool ret = false; //Valeur de retour
    vector<vector<Point*> >::iterator currentO = this->obstacles.begin(); //Iterateur pour parcourire les obstacles
    while(!ret && currentO != this->obstacles.end()){
        //Pour chaque obstacle on regarde les intersections entre le lien et l'obstacle
        vector<Point*> intersections;
        vector<Point*> intersectionsUnique;
        vector<Point*>::iterator currentPI;
        Link* tmpL = NULL;
        Point* tmpP = NULL;
        //On parcourt tous les points de l'obstacle
        vector<Point*>::iterator currentP = currentO->begin();
        Point* last = NULL; //Denier point visiter
        while(currentP != currentO->end()){
            if(last != NULL){
                tmpL = new Link(last,(*currentP));
                tmpP = Link::getIntersection(tmpL,link);
                if(tmpP != NULL){
                    intersections.push_back(tmpP);
                }
                delete tmpL;
            }
            last = (*currentP);
            currentP++;
        }
        //Pour le dernier bord de l'obstacle
        tmpL = new Link(last,(*currentO->begin()));
        tmpP = Link::getIntersection(tmpL,link);
        if(tmpP != NULL){
            intersections.push_back(tmpP);
        }
        delete tmpL;

        //Epure la liste des intersection afin de supprimer les doublons
        currentPI = intersections.begin();
        while(currentPI != intersections.end()){
            bool existe = false;
            currentP = intersectionsUnique.begin();
            while(!existe && currentP != intersectionsUnique.end()){
                if((**currentP) == (**currentPI)){
                    existe = true;
                }
                currentP++;
            }
            if(!existe){
                intersectionsUnique.push_back((*currentPI));
            }
            currentPI++;
        }
        //Si le nombre d'intersection est supperieur a 1 alors il y a forcement contact
        if(intersectionsUnique.size() > 1){
            currentPI = intersectionsUnique.begin();
            while(currentPI != intersectionsUnique.end()){
                currentPI++;
            }
            ret = true;
        }
        else if(intersectionsUnique.size() == 1){
            //Si il n'y a qu'un point d'intersection
            //On verifie si ce point fait partie des points de l'obstacle, si il n'en fait pas partie alors il y a intersection
            currentPI = intersectionsUnique.begin();
            currentP = currentO->begin();
            ret = true;
            while(ret && currentP != currentO->end()){
                if((**currentP) == (**currentPI)){
                    ret = false;
                }
                currentP++;
            }

            //On verifie si le vecteur n'est pas inclue dans l'obstacle
            if(!ret){

            }
        }

        currentPI = intersections.begin();
        while(currentPI != intersections.end()){
            delete (*currentPI);
            currentPI++;
        }
        currentO++;
    }
    return ret;
}
ostream & operator<<( ostream &out, MweraBase m){
    out << m.gr;
    return out;
}
